#ifndef EDITORMANAGER_H
#define EDITORMANAGER_H

#include "prep.h"
#include <wx/list.h>
#include <wx/treectrl.h>
#include <wx/hashmap.h>
#include <wx/filename.h>
#include "manager.h"
#include "M_Code_exception.h"
#include "globals.h"

extern int ID_NBEditorManager;
extern int ID_EditorManager;
extern int idEditorManagerCheckFiles;
extern int ID_EditorManagerCloseButton;

class EditorBase;
class M_Code_AuiNotebook;
class wxAuiNotebookEvent;
class EditorColourSet;
class M_Code_Project;
class ProjectFile;
class M_Code_Editor;
class M_Code_StyledTextCtrl;
class ListCtrlLogger;
class LoaderBase;
struct EditorManagerInternalData;
class SearchResultsLog;

struct cbNotebookStack {
  cbNotebookStack( wxWindow* a_pWindow = nullptr )
    : window( a_pWindow ),
      next( nullptr ) {}

  wxWindow* window;
  cbNotebookStack* next;
};


class EditorManager : public Mgr<EditorManager>, public wxEvtHandler {
    friend class Mgr<EditorManager>;
    static bool s_CanShutdown;
  public:
    EditorManager& operator=( M_Code_unused const EditorManager& rhs ) {
      m_Throw( _T( "不能分配一个 EditorManager* !!!" ) );
      return *this;
    }
    friend class Manager;
    static bool CanShutdown() { return s_CanShutdown; }
    M_Code_AuiNotebook* GetNotebook() { return m_pNotebook; }
    cbNotebookStack* GetNotebookStack();
    void DeleteNotebookStack();
    void RebuildNotebookStack();
    void RecreateOpenEditorStyles();
    int GetEditorsCount();
    EditorBase* IsOpen( const wxString& filename );
    M_Code_Editor* Open( const wxString& filename, int pos = 0, ProjectFile* data = nullptr );
    M_Code_Editor* Open( LoaderBase* fileLdr, const wxString& filename, int pos = 0, ProjectFile* data = nullptr );
    EditorBase* GetEditor( int index );
    EditorBase* GetEditor( const wxString& filename ) { return IsOpen( filename ); }
    EditorBase* GetActiveEditor();
    M_Code_Editor* GetBuiltinEditor( EditorBase* eb );
    int FindPageFromEditor( EditorBase* eb );
    M_Code_Editor* IsBuiltinOpen( const wxString& filename ) { return GetBuiltinEditor( IsOpen( filename ) ); }
    M_Code_Editor* GetBuiltinEditor( int index ) { return GetBuiltinEditor( GetEditor( index ) ); }
    M_Code_Editor* GetBuiltinEditor( const wxString& filename ) { return IsBuiltinOpen( filename ); }
    M_Code_Editor* GetBuiltinActiveEditor() { return GetBuiltinEditor( GetActiveEditor() ); }
    void ActivateNext();
    void ActivatePrevious();
    void SetActiveEditor( EditorBase* ed );
    EditorColourSet* GetColourSet() { return m_Theme; }
    void SetColourSet( EditorColourSet* theme );
    M_Code_Editor* New( const wxString& newFileName = wxEmptyString );
    void AddCustomEditor( EditorBase* eb );
    void RemoveCustomEditor( EditorBase* eb );
    bool UpdateProjectFiles( M_Code_Project* project );
    bool SwapActiveHeaderSource();
    bool OpenContainingFolder();
    bool CloseActive( bool dontsave = false );
    bool Close( const wxString& filename, bool dontsave = false );
    bool Close( EditorBase* editor, bool dontsave = false );
    bool Close( int index, bool dontsave = false );
    bool QueryClose( EditorBase* editor );
    bool QueryCloseAll();
    bool CloseAll( bool dontsave = false );
    bool CloseAllExcept( EditorBase* editor, bool dontsave = false );
    bool CloseAllInTabCtrl( bool dontsave = false );
    bool CloseAllInTabCtrlExcept( EditorBase* editor, bool dontsave = false );
    bool Save( const wxString& filename );
    bool Save( int index );
    bool SaveActive();
    bool SaveAs( int index );
    bool SaveActiveAs();
    bool SaveAll();
    void HideNotebook();
    void ShowNotebook();
    void CheckForExternallyModifiedFiles();
    void SetZoom( int zoom );
    int GetZoom()const;
    void MarkReadOnly( int page, bool readOnly = true );
    wxString GetSelectionClipboard();
    void SetSelectionClipboard( const wxString& data );
  private:
    void OnGenericContextMenuHandler( wxCommandEvent& event );
    void OnPageChanged( wxAuiNotebookEvent& event );
    void OnPageChanging( wxAuiNotebookEvent& event );
    void OnPageClose( wxAuiNotebookEvent& event );
    void OnPageContextMenu( wxAuiNotebookEvent& event );
    void OnClose( wxCommandEvent& event );
    void OnCloseAll( wxCommandEvent& event );
    void OnCloseAllOthers( wxCommandEvent& event );
    void OnSave( wxCommandEvent& event );
    void OnSaveAll( wxCommandEvent& event );
    void OnSwapHeaderSource( wxCommandEvent& event );
    void OnOpenContainingFolder( wxCommandEvent& event );
    void OnTabPosition( wxCommandEvent& event );
    void OnProperties( wxCommandEvent& event );
    void OnAddFileToProject( wxCommandEvent& event );
    void OnRemoveFileFromProject( wxCommandEvent& event );
    void OnShowFileInTree( wxCommandEvent& event );
    void OnAppDoneStartup( wxCommandEvent& event );
    void OnAppStartShutdown( wxCommandEvent& event );
    void OnUpdateUI( wxUpdateUIEvent& event );
    void OnTreeItemSelected( wxTreeEvent &event );
    void OnTreeItemActivated( wxTreeEvent &event );
    void OnTreeItemRightClick( wxTreeEvent &event );
    void CollectDefines( CodeBlocksEvent& event );
  protected:
    void AddEditorBase( EditorBase* eb );
    void RemoveEditorBase( EditorBase* eb, bool deleteObject = true );
    M_Code_Editor* InternalGetBuiltinEditor( int page );
    EditorBase* InternalGetEditorBase( int page );
  private:
    EditorManager( M_Code_unused const EditorManager& rhs );
    EditorManager();
    ~EditorManager();
    void OnCheckForModifiedFiles( wxCommandEvent& event );
    bool IsHeaderSource( const wxFileName& candidateFile, const wxFileName& activeFile, FileType ftActive, bool& isCandidate );
    wxFileName FindHeaderSource( const wxArrayString& candidateFilesArray, const wxFileName& activeFile, bool& isCandidate );
    bool CloseEditors( const std::vector<EditorBase*> &editors, bool dontsave = false );
    void GetEditorsInTabCtrl( std::vector<EditorBase*> &editors, EditorBase *editor );
    M_Code_AuiNotebook* m_pNotebook;
    cbNotebookStack* m_pNotebookStackHead;
    cbNotebookStack* m_pNotebookStackTail;
    size_t m_nNotebookStackSize;
    EditorColourSet* m_Theme;
    int m_Zoom;
    bool m_isCheckingForExternallyModifiedFiles;
    friend struct EditorManagerInternalData;
    EditorManagerInternalData* m_pData;
    DECLARE_EVENT_TABLE()
};

#endif
